home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / 4_0 / GNUUCP_2 / SOURCE / SYSDEP.UNI < prev    next >
Text File  |  1989-07-31  |  13KB  |  577 lines

  1. /*
  2.  * @(#)sysdep.unix 1.11 87/09/29    Copyright 1987 Free Software Foundation, Inc.
  3.  *
  4.  * Copying and use of this program are controlled by the terms of the
  5.  * GNU Emacs General Public License.
  6.  */
  7.  
  8. #ifndef lint
  9. char sysdep_version[] = "@(#)sysdep.unix gnuucp Version hoptoad-1.11";
  10. #endif
  11.  
  12. #ifdef BSD
  13. /* Unix Berserkeley systems */
  14. #include <stdio.h>
  15. #include <ctype.h>
  16. #include <sgtty.h>
  17. #include <sys/param.h>
  18. #include <sys/file.h>
  19. #include <sys/time.h>
  20. #include <signal.h>
  21. #include <setjmp.h>
  22. #include <strings.h>
  23. #include <sys/dir.h>
  24.  
  25. #define    dirent    direct    /* For POSIX compatability */
  26. extern char *strtok();
  27.  
  28. #define    UNIX
  29. #define    NAMESIZE    MAXPATHLEN
  30. #endif
  31.  
  32. #ifdef SYSV
  33. /* Unix System V */
  34. #include <stdio.h>
  35. #include <ctype.h>
  36. #include <fcntl.h>
  37. #include <termio.h>
  38. #include <signal.h>
  39. #include <setjmp.h>
  40. #include <string.h>
  41. #include <dirent.h>        /* SVR3 -- older has to use PD version */
  42.  
  43. #define    UNIX
  44. #endif
  45.  
  46. #include "uucp.h"
  47. #include "sysdep.h"
  48.  
  49. /* Stuff common to all Unix systems */
  50. #define    STDIN        0
  51. #define    CONTROL        "/usr/lib/uucp/gnuucp.ctl"
  52. #define    O_BINARY    0    /* No distinction between text and binary */
  53.  
  54. /*
  55.  * Exported variables
  56.  */
  57. char     sysdep_control[] = CONTROL;
  58.  
  59.  
  60. /* Our variables */
  61. static jmp_buf alarming;            /* For read timeouts */
  62.  
  63. #ifdef BSD
  64.     struct sgttyb atermio, btermio;
  65. #endif
  66. #ifdef SYSV
  67.     struct termio atermio, btermio;
  68. #endif
  69.  
  70. int    fdtty;                /* File descriptor for tty line */
  71.  
  72. void sigint();                /* Forward declaration */
  73.  
  74. /*
  75.  * Translation between integer baud rates and Unix baud rates (grumble)
  76.  */
  77. static struct baudtab {
  78.     int    baudrate, damn_B_code;
  79. } baudtab[] = {
  80.     50,    B50,
  81.     75,    B75,
  82.     110,    B110,
  83.     134,    B134,
  84.     150,    B150,
  85.     200,    B200,
  86.     300,    B300,
  87.     600,    B600,
  88.     1200,    B1200,
  89.     1800,    B1800,
  90.     2400,    B2400,
  91.     4800,    B4800,
  92.     9600,    B9600,
  93.     19200,    B19200,
  94.     38400,    B38400,
  95. };
  96.  
  97. static int
  98. damn_B(baud)
  99. {
  100.     register struct baudtab *b;
  101.  
  102.     for (b = baudtab; b->baudrate < baud; b++) continue;
  103.     if (b->baudrate == baud)
  104.         return b->damn_B_code;
  105.     return EXTB;    /* Maybe this'll get clocking from the modem */
  106. }
  107.  
  108. /*
  109.  * Open the serial line for an incoming call.
  110.  * Argument of NULL or empty string means stdin.
  111.  */
  112. int
  113. openline(ttynam, baud)
  114.     char    *ttynam;
  115.     int    baud;
  116. {
  117.     int ontheline = !(ttynam && ttynam[0]);    /* FIXME, this is garbage */
  118.  
  119. #ifdef BSD
  120.     /* Berserkeley version */
  121.     if (ontheline) {
  122.         fdtty = STDIN;
  123.     } else if ((fdtty = open(ttynam, O_RDWR)) < 0) {
  124.         if (DEBUG_LEVEL(0)) perror(ttynam);
  125.         exit(1);
  126.     }
  127.     ioctl(fdtty, TIOCGETP, &atermio);
  128.     btermio = atermio;
  129.     btermio.sg_flags |= RAW;
  130.     btermio.sg_flags &= ~(ECHO|XTABS);
  131.     if (!ontheline)
  132.         btermio.sg_ispeed = btermio.sg_ospeed = damn_B(baud);
  133.     ioctl(fdtty, TIOCSETN, &btermio);
  134.     signal(SIGINT,sigint);
  135. #endif
  136.  
  137. #ifdef SYSV
  138.     /* Missed'em Five version */
  139.     if (ontheline) {
  140.         fdtty = STDIN;
  141.     } else if ((fdtty = open(ttynam, O_RDWR)) < 0) {
  142.         if (DEBUG_LEVEL(0)) perror(ttynam);
  143.         exit(1);
  144.     }
  145.     ioctl(fdtty,TCGETA,&atermio);
  146.     btermio = atermio;
  147.     btermio.c_iflag = btermio.c_oflag = btermio.c_lflag = 0;
  148.     btermio.c_cc[VMIN] = 1;
  149.     btermio.c_cc[VTIME] = 0;
  150.     if (!ontheline)
  151.         btermio.c_cflag = (btermio.c_cflag & ~CBAUD) | damn_B(baud);
  152.     ioctl(fdtty,TCSETA,&btermio);
  153. #endif
  154.  
  155.     signal(SIGINT,sigint);
  156.     signal(SIGTERM,sigint);
  157.     return SUCCESS;
  158. }
  159.  
  160. /*
  161.  * Open the serial line for an outgoing call.
  162.  */
  163. int
  164. openout(ttynam, baud)
  165.     char    *ttynam;
  166.     int    baud;
  167. {
  168.     char    devname[PORTNAME_SIZE*2+SLOP];
  169.  
  170.     /* Set cleanup monitor */
  171.     signal(SIGINT, sigint);
  172.     signal(SIGTERM, sigint);
  173.  
  174.     /* Lock against several uucp's trying to use the same line */
  175.     if (ttylock(ttynam) != SUCCESS)
  176.         return FAIL;
  177.     
  178.     sprintf(devname, "/dev/%s", ttynam);
  179.  
  180. #ifdef BSD
  181.     /* Berserkeley version */
  182.     if ((fdtty = open(devname, O_RDWR)) < 0) {
  183.         if (DEBUG_LEVEL(0)) perror(devname);
  184.         ttyunlock();
  185.         return FAIL;
  186.     }
  187.     ioctl(fdtty, TIOCGETP, &atermio);
  188.     btermio = atermio;
  189.     btermio.sg_flags |= RAW;
  190.     btermio.sg_flags &= ~(ECHO|XTABS);
  191.     btermio.sg_ispeed = btermio.sg_ospeed = damn_B(baud);
  192.     ioctl(fdtty, TIOCSETN, &btermio);
  193. #endif
  194.  
  195. #ifdef SYSV
  196.     /* Missed'em Five version */
  197.     if ((fdtty = open(devname, O_RDWR)) < 0) {
  198.         if (DEBUG_LEVEL(0)) perror(devname);
  199.         return FAIL;
  200.     }
  201.     ioctl(fdtty,TCGETA,&atermio);
  202.     btermio = atermio;
  203.     btermio.c_iflag = btermio.c_oflag = btermio.c_lflag = 0;
  204.     btermio.c_cc[VMIN] = 1;
  205.     btermio.c_cc[VTIME] = 0;
  206.     btermio.c_cflag = (btermio.c_cflag & ~CBAUD) | damn_B(baud);
  207.     ioctl(fdtty,TCSETA,&btermio);
  208. #endif
  209.  
  210.     return SUCCESS;
  211. }
  212.  
  213. /*
  214.  * Basement level I/O routines
  215.  *
  216.  * xwrite() writes a character string to the serial port
  217.  * xgetc() returns a character from the serial port, or an EOF for timeout.
  218.  * sigint() restores the state of the serial port on exit.
  219.  * hangup() hangs up the serial port (e.g. drop DTR).
  220.  */
  221.  
  222. void
  223. sigint()
  224. {
  225.  
  226.     logit("INTERRUPTED", "terminating");
  227.     hangup();
  228.     exit(0);
  229. }
  230.  
  231.  
  232.  
  233. /* Real simple for Unix */
  234. xwrite(buf,ctr)
  235.     char *buf;
  236.     int ctr;
  237. {
  238.     return write(fdtty, buf, ctr);
  239. }
  240.  
  241.  
  242. /*
  243.  * Serial port reading routines 
  244.  */
  245. sigalrm()
  246. {
  247.     longjmp(alarming, 1);
  248. }
  249.  
  250. /*
  251.  * FIXME:  This is really slow; it does 4 system calls per byte!
  252.  */
  253. int
  254. xgetc()
  255. {
  256.     char data;
  257.     int status;
  258.  
  259.     signal(SIGALRM,sigalrm);
  260.     alarm(BYTE_TIMEOUT);
  261.     if (setjmp(alarming) == 0) 
  262.     {
  263.         status = read(fdtty,&data,1);
  264.         alarm(0);
  265.         if (status == 1)    /* the read worked, returning 1 char */
  266.             return(data & 0xFF);
  267.     }
  268.     /* Error on serial port, or timeout. */
  269.     return(EOF);
  270. }
  271.  
  272. /*
  273.  * hangup(): hang up the 'fone.
  274.  */
  275. int
  276. hangup()
  277. {
  278.  
  279.     /* Restore terminal settings on dialout line */
  280. #ifdef BSD
  281.     ioctl(fdtty, TIOCSETN, &atermio);
  282. #endif
  283.  
  284. #ifdef SYSV
  285.     ioctl(fdtty,TCSETA,&atermio);
  286. #endif
  287.  
  288.     if (0 != close(fdtty)) {
  289.         if(DEBUG_LEVEL(0))  perror("closing tty");
  290.     }
  291.  
  292.     ttyunlock();
  293.  
  294.     sleep(2);        /* To be sure DTR stays down that long */
  295. }
  296.  
  297.  
  298. /*
  299.  * Create a temporary file name for receiving a file into.
  300.  * "name" is the name we will actually eventually want to use for the file.
  301.  * We currently ignore it, but some OS's that can't move files around
  302.  * easily might want to e.g. put the temp file into the same directory
  303.  * that this file is going into.
  304.  *
  305.  * FIXME:
  306.  * This interface should be able to return a "possible" filename, and
  307.  * be re-called if the name is already in use, to get another.
  308.  * This avoids checking here whether the name is good -- saving system calls.
  309.  */
  310. char *
  311. temp_filename(name)
  312.     register char *name;
  313. {
  314.     static char tname[NAMESIZE];
  315.     static int  count = 0;
  316.  
  317.     if (ourpid == 0)
  318.         ourpid = getpid();
  319.     (void) sprintf(tname, "TM.u%d.%d", ourpid, count++);
  320.     DEBUG(7, "Using temp file %s\n", tname);
  321.     return tname;
  322. }
  323.  
  324.  
  325. /*
  326.  * Transform a filename from a uucp packet (in Unix format) into a local
  327.  * filename that will work in the local file system.
  328.  */
  329. char *
  330. munge_filename(name)
  331.     register char *name;
  332. {
  333.     register char *p;
  334.     static char buffer[NAMESIZE+SLOP];
  335.     int len, hostlen;
  336.  
  337.     DEBUG(7, "Munge_filename  input: %s\n", name);
  338.  
  339.     /* FIXME: Security checking goes here! */
  340.  
  341.     if (name[0] == '~') {
  342.         /* Handle user-relative names -- ~ or ~uucp turns to Pubdir */
  343.         if (name[1] == '/')
  344.             p = &name[1];
  345.         else if (!strncmp("~uucp/", name, 6))
  346.             p = &name[5];
  347.         else {
  348.             p = NULL;        /* Neither of the above */
  349.             goto out;
  350.         }
  351.         strcpy(buffer, Pubdir);
  352.         strcat(buffer, p);
  353.         p = buffer;
  354.         goto out;
  355.     }
  356.  
  357. #ifdef SUBDIR
  358.     /* Berkeley Unix subdirectory hack.
  359.      * Full pathnames go through OK.
  360.      * D.myname*    -> D.myname/D.myname*
  361.      * D.*        -> D./D.*
  362.      * C.*        -> C./C.*
  363.      * LCK.*    -> LCK..*
  364.      * otherwise left alone (e.g. X.*, STST.*).
  365.      * FIXME: I hear Honey Danber has a slightly different scheme.
  366.      * In particular, STST's go in a directory.
  367.      */
  368.     if (name[0] != '/') {
  369.         if (name[1] == '.' &&
  370.             (name[0] == 'C' || name[0] == 'D')) {
  371.             len = strlen(name);
  372.             hostlen = strlen(Myname);
  373.             if (hostlen > 7) hostlen = 7;
  374.             /* Check D.mynameAxxxx case */
  375.             if (name[0] == 'D' && len == hostlen + 2 + 5 &&
  376.                 !strncmp(&name[2], Myname, hostlen))
  377.                 len = 2 + hostlen;    /* "D."+name */
  378.             else
  379.                 len = 2;        /* Just "D." */
  380.             strcpy(buffer, name);
  381.             buffer[len] = '/';
  382.             strcpy(buffer+len+1, name);
  383.             p = buffer;
  384.             goto out;
  385.         }
  386.         if (strncmp("LCK.", name, 4) == 0 &&
  387.             strcmp("LCK.XQT", name) != 0) {
  388.             /* For some reason, old uucp uses "LCK..xxx" rather
  389.              * than "LCK.xxx".  Except for LCK.XQT.  Foo.
  390.              */
  391.             strcpy(buffer, "LCK..");
  392.             strcpy(buffer+5, name+4);
  393.             p = buffer;
  394.             goto out;
  395.         }
  396.     }
  397. #endif
  398.  
  399.     p = name;        /* Let it through as-is. */
  400.  
  401. out:
  402.     DEBUG(7, "Munge_filename output: %s\n", p);
  403.     return p;
  404. }
  405.  
  406. /*
  407.  * Uucp work queue scan.
  408.  *
  409.  * gotsome = work_scan(hostname, type);
  410.  * workfile = work_next();
  411.  * void work_done();
  412.  */
  413.  
  414. /*
  415.  * Local variables of the work queue scanner -- not visible to outsiders
  416.  *
  417.  * Workhost and worktype are always null-terminated; keeping their lengths
  418.  * is just a performance hack.  Workprefix is NOT null terminated; various
  419.  * people copy things after it and use the whole string.  Workprefix is
  420.  * exactly workplen long; to append something, strcpy(workprefix+workplen, ...)
  421.  */
  422. #define MAX_TYPE    10
  423. static DIR    *workdir = (DIR *)NULL;
  424. static struct dirent    *workfile;
  425. static char    workhost[MAX_HOST+1];
  426. static int    workhlen;
  427. static char    worktype[MAX_TYPE+1];
  428. static int    worktlen;
  429. static char    workfirst = 0;
  430. /* FIXME, at the moment this can be local to work_scan() */
  431. static char    workprefix[MAX_TYPE+1+MAX_HOST+1+MAX_TYPE+1+MAX_HOST+6+SLOP];
  432.         /*       D        . hoptoad  / D        . hoptoad  N1234\0 */
  433. static int    workplen;
  434.  
  435. void
  436. work_done()
  437. {
  438.     if (workdir)
  439.         closedir(workdir);
  440.     workdir = (DIR *) NULL;
  441.     workfile = (struct dirent *) NULL;
  442.     workfirst = 0;
  443. }
  444.  
  445.  
  446. int
  447. work_scan(host, type)
  448.     char *host;
  449.     char *type;
  450. {
  451.     char *p;
  452.  
  453.     if (!host)
  454.         host = "";
  455.  
  456.     /* If called twice in a row, don't thrash the disk again */
  457.     if (strcmp(workhost, host) == SAME &&
  458.         strcmp(worktype, type) == SAME && workfile)
  459.         return 1;
  460.  
  461.     if (workdir) work_done();        /* Clean up prev call */
  462.  
  463.     workfirst = 1;                /* Initialize for work_next */
  464.     workhlen = strlen(host);
  465.     if (workhlen > sizeof (workhost) -1) abort();
  466.     strcpy(workhost, host);
  467.     if (workhlen > 7) workhlen = 7;        /* Unix uucp limit */
  468.     worktlen = strlen(type);
  469.     if (worktlen > sizeof (worktype) -1) abort();
  470.     strcpy(worktype, type);
  471.  
  472.     /* Figure out which subdirectory this class of files is in. */
  473.     /* FIXME: doesn't handle "all D. files" since D.myname is separate. */
  474.     sprintf(workprefix, "%s.%s", worktype, workhost);
  475.     p = munge_filename(workprefix);
  476.     strcpy(workprefix, p);
  477.     p = index(workprefix, '/');
  478.     if (p)
  479.         workplen = 1 + p - workprefix;    /* Prefix ends after '/' */
  480.     else
  481.         workplen = 0;        /* No / in munged; hence no dir */
  482.     workprefix[workplen] = '\0';
  483.     DEBUG(8, "Work prefix is =%s=\n", workprefix);
  484.  
  485.     strcpy(workprefix+workplen, ".");
  486.     workdir = opendir(workprefix);    /* Open whatever directory */
  487.     if (workdir == NULL) {
  488.         DEBUG(0, "Can't open queue directory %s\n", workprefix);
  489.         return 0;            /* No work */
  490.     }
  491.  
  492.     return work_look();
  493. }
  494.  
  495.  
  496. static int
  497. work_look()
  498. {
  499.     int len;
  500.  
  501.     for (;;) {
  502.         workfile = readdir(workdir);
  503.         if (workfile == NULL) {
  504.             DEBUG(7, "work_look: end of dir\n", 0);
  505.             work_done();
  506.             return 0;        /* No work */
  507.         }
  508.         DEBUG(8, "work_look readdir %s\n", workfile->d_name);
  509.  
  510.         /* Is it the right type? */
  511.         if (strncmp(workfile->d_name, worktype, worktlen) == SAME
  512.             && workfile->d_name[worktlen] == '.') {
  513.             /* see if it matches the hostname */
  514.             len = strlen(workfile->d_name);
  515.             /*         "C"        "." "hoptoad" "Xnnnn" */
  516.             if (workhlen == 0 || 
  517.                 (len == worktlen + 1 + workhlen + 5 && 
  518.                  !strncmp(workhost, workfile->d_name+2, workhlen))
  519.                ) {
  520.                 /* Found an entry! */
  521.                 /* FIXME, check grade letter! */
  522.                 DEBUG(7, "work_look found %s\n", workfile->d_name);
  523.                 return 1;    /* Found work */
  524.             }
  525.         }
  526.     }
  527.     /* NOTREACHED */
  528. }
  529.  
  530.  
  531. char *
  532. work_next()
  533. {
  534.     static char buffer[NAMESIZE+SLOP];
  535.  
  536.     if (!workfirst) {
  537.         if (!workfile || !work_look())
  538.             return (char *)NULL;
  539.     }
  540.     workfirst = 0;
  541.  
  542.     if (strncmp("LCK..", workfile->d_name, 5) == 0) {
  543.         /*
  544.          * For some reason, old uucp uses "LCK..xxx" rather
  545.          * than "LCK.xxx" like it does everywhere else.
  546.          * We return the "LCK.xxx" form.
  547.          */
  548.         strcpy(buffer, "LCK.");
  549.         strcpy(buffer+4, workfile->d_name+5);
  550.         return buffer;
  551.     }
  552.     return workfile->d_name;
  553. }
  554.  
  555. /*
  556.  * Routine to return a string that gives the current date and time, and
  557.  * identifies the current process, if on a multiprocess system.
  558.  */
  559. char *
  560. time_and_pid()
  561. {
  562.     long clock;
  563.     struct tm *tm;
  564.     static char format[] = "%d/%d-%d:%02d:%02d-%d";
  565.     static char outbuf[sizeof(format)];
  566.  
  567.     (void) time(&clock);
  568.     tm = localtime(&clock);
  569.     if (ourpid == 0)
  570.         ourpid = getpid();
  571.     sprintf(outbuf, format,
  572.         tm->tm_mon+1, tm->tm_mday,
  573.         tm->tm_hour, tm->tm_min, tm->tm_sec,
  574.         ourpid);
  575.     return outbuf;
  576. }
  577.